﻿using MyHome.Server.PluginBase;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace MyHome.Server.PluginManagement
{
    /// <summary>
    /// Helper class to load plugin types from all .dlls in the plugin folder
    /// </summary>
    internal static class PluginAssemblyHelper
    {
        private const string PLUGIN_FOLDER = "\\Plugins\\";

        /// <summary>
        /// Loads all plugin types from the disk asynchronous.
        /// </summary>
        /// <returns>All plugin types with the full names keys.</returns>
        internal static Task<IDictionary<string, Type>> LoadFromDiskAsync()
        {
            return Task.Run(() => Load());
        }

        private static IDictionary<string, Type> Load()
        {
            var pluginTypes = new Dictionary<string, Type>();
            Trace.TraceInformation("Loading plugins");
            string fullPath = AppDomain.CurrentDomain.BaseDirectory + PLUGIN_FOLDER;
            try
            {
                var directoryInfo = new DirectoryInfo(fullPath);
                var assemblyFiles = directoryInfo.GetFiles("*.dll", SearchOption.AllDirectories);
                foreach (var fileInfo in assemblyFiles)
                {
                    try
                    {
                        var assembly = Assembly.LoadFrom(fileInfo.FullName);
                        foreach (var type in assembly.GetTypes())
                        {
                            if (typeof(IPlugin).IsAssignableFrom(type))
                            {
                                try
                                {
                                    pluginTypes.Add(type.FullName, type);
                                    Trace.TraceInformation("Loaded plugin type {0} from the assembly {1} succesfully", type.FullName, fileInfo.Name);
                                }
                                catch (Exception e)
                                {
                                    Trace.TraceError("An exception occured while loading the plugin type {0} from the assembly {1}\nThe exception was:\n{2}", type.FullName, fileInfo.Name, e.ToString());
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Trace.TraceError("An exception occured while loading the assembly {0}\nThe exception was:\n{1}", fileInfo.Name, e.ToString());
                    }
                }
                Trace.TraceInformation("Loaded {0} plugin types succesfully", pluginTypes.Count);
            }
            catch (Exception e)
            {
                Trace.TraceError("An exception occured while loading the plugin types from the folder {0}\nThe exception was:\n{1}", fullPath, e.ToString());
            }

            return pluginTypes;
        }
    }
}